/*
 * @[H]:  Copyright (c) 2021 Phytium Information Technology, Inc. 
 * 
 *  SPDX-License-Identifier: Apache-2.0. 
 * 
 * @Date: 2021-08-17 14:56:40
 * @LastEditTime: 2021-08-18 16:45:29
 * @Description:  Description of file
 * @Modify History: 
 * * * Ver   Who        Date         Changes
 * * ----- ------     --------    --------------------------------------
 */
#include "fgdma.h"
#include "fgdma_hw.h"
#include "ft_debug.h"
#define FGDMA_IRQ_DEBUG_TAG "FGDMA_IRQ"
#define FGDMA_IRQ_ERROR(format, ...) FT_DEBUG_PRINT_E(FGDMA_IRQ_DEBUG_TAG, format, ##__VA_ARGS__)
#define FGDMA_IRQ_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FGDMA_IRQ_DEBUG_TAG, format, ##__VA_ARGS__)
#define FGDMA_IRQ_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FGDMA_IRQ_DEBUG_TAG, format, ##__VA_ARGS__)
#define FGDMA_IRQ_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FGDMA_IRQ_DEBUG_TAG, format, ##__VA_ARGS__)

void FGdmaIrqHandler(s32 vector, void *args)
{
    FGdma *instance_p = (FGdma *)args;
    u32 reg_value, chan_reg_value;
    u32 i;

    reg_value = FGDMA_READREG(instance_p->config.base_address, FGDMA_GLOBAL_INTR_STATE_OFFSET);
    /* Disable DMAC inerrupts. We'll enable them after processing chanels */
    FGdmaIrqDisable(instance_p);
    for (i = 0; i < FGDMA_CHANNEL_MAX_NUM; i++)
    {
        if (!(reg_value & BIT(i)))
        {
            continue;
        }

        chan_reg_value = FGDMA_READREG(instance_p->config.dma_channel_config[i].dma_channel_addr,
                                       FGDMA_CHX_INT_STATE_OFFSET);
        chan_reg_value &= FGDMA_CHX_INT_STATE_ALL_MASK;
        FGDMA_WRITEREG(instance_p->config.dma_channel_config[i].dma_channel_addr,
                       FGDMA_CHX_INT_STATE_OFFSET,
                       FGDMA_CHX_INT_STATE_TRANS_END_MASK);

        if (chan_reg_value & FGDMA_CHX_INT_STATE_TRANS_END_MASK)
        {
            if (instance_p->irq_status_cb)
                instance_p->irq_status_cb(FGDMA_IRQ_STATUS_TRANS_END, instance_p->irq_status_args);
        }
        else if (chan_reg_value & FGDMA_CHX_INT_STATE_BDL_END_MASK)
        {
            if (instance_p->irq_status_cb)
                instance_p->irq_status_cb(FGDMA_IRQ_STATUS_BDL_END, instance_p->irq_status_args);
            FGDMA_IRQ_DEBUG_E("----dma not completed. bdl end. chan_status: %x\n",
                              chan_reg_value);
        }
        else if (chan_reg_value & FGDMA_CHX_INT_STATE_BUSY_MASK)
        {
            if (instance_p->irq_status_cb)
                instance_p->irq_status_cb(FGDMA_IRQ_STATUS_BUSY, instance_p->irq_status_args);
            FGDMA_IRQ_DEBUG_E("----dma not completed. status busy. chan_status: %x\n",
                              chan_reg_value);
        }
        else if (chan_reg_value & FGDMA_CHX_INT_STATE_FIFO_EMPTY_MASK)
        {
            if (instance_p->irq_status_cb)
                instance_p->irq_status_cb(FGDMA_IRQ_STATUS_FIFO_EMPTY, instance_p->irq_status_args);
            FGDMA_IRQ_DEBUG_E("----dma not completed. fifo empty. chan_status: %x\n",
                              chan_reg_value);
        }
        else if (chan_reg_value & FGDMA_CHX_INT_STATE_FIFO_FULL_MASK)
        {
            if (instance_p->irq_status_cb)
                instance_p->irq_status_cb(FGDMA_IRQ_STATUS_FIFO_FULL, instance_p->irq_status_args);
            FGDMA_IRQ_DEBUG_E("----dma not completed. fifo full. chan_status: %x\n",
                              chan_reg_value);
        }
        else
        {
            if (instance_p->irq_status_cb)
                instance_p->irq_status_cb(FGDMA_IRQ_STATUS_OTHER, instance_p->irq_status_args);
            FGDMA_IRQ_DEBUG_E("----dma not completed. chan_status: %x\n",
                              chan_reg_value);
        }
    }
    FGdmaIrqEnable(instance_p);
}

ft_error_t FGdmaIrqSetHandler(FGdma *instance_p, void *func_pointer, void *call_back_ref)
{
    ft_error_t status;
    FT_ASSERTNONVOID(instance_p != NULL);
    FT_ASSERTNONVOID(func_pointer != NULL);
    FT_ASSERTNONVOID(instance_p->is_ready == (u32)FT_COMPONENT_IS_READY);
    instance_p->irq_status_cb = (FGdmaChxIrqStatus)func_pointer;
    instance_p->irq_status_args = call_back_ref;
    return FT_SUCCESS;
}